# -*- coding: utf-8 -*-
class NoTrainError(Exception):
	def __init__(self, number):
		self.number = number
	def __str__(self):
		return 'No train with this number: '+str(number)

def correct(s):
	return s.replace('e&#039;',"e'")

def train_existence(number):
	train = Train.all().filter('number = ', number).order('-checked').get()
	if train:
		from datetime import timedelta, date, time, datetime
		if (train.checked-datetime.combine(date.today(),time(0)))>timedelta(0):
			return train.existent
	try: get_train_page(number); return True
	except NoTrainError: return False

def get_train_page(number, summary=False, lang='IT'):
	trenitaliaurl = "http://mobile.viaggiatreno.com/viaggiatreno/mobile/scheda?%s"
	import urllib
	params = {
		'numeroTreno': number,
		'tipoRicerca': 'numero',
		'lang': lang,
		}
	if not summary: params['dettaglio']='visualizza'
	params = urllib.urlencode(params)
	page = correct(urllib.urlopen(trenitaliaurl % params).read())
	if '<h1> </h1>' in page:
		raise NoTrainError(number)
	return page

def compute_delay(actual, scheduled):
	MAXADVANCE = 2*60 # two hours
	ADAY = 24*60
	from datetime import timedelta
	if actual==None or scheduled==None: return None
	actual = timedelta(hours=actual.hour, minutes=actual.minute)
	scheduled = timedelta(hours=scheduled.hour, minutes=scheduled.minute)
	delay = actual-scheduled
	delay = delay.days*60*24+delay.seconds/60
	return ((delay+MAXADVANCE)%ADAY) - MAXADVANCE

def punctuality(delay):
	if delay<=0: return 0
	elif delay<15: return 1
	elif delay<30: return 2
	elif delay<60: return 3
	else: return 4

class TrainStop:
	def __init__(self, name, scheduledTime, actualTime,
		scheduledPlatform, actualPlatform, inTheFuture=False):
		self.name = name
		self.scheduledTime = scheduledTime
		self.actualTime = actualTime
		self.scheduledPlatform = scheduledPlatform
		self.actualPlatform = actualPlatform
		self.inTheFuture = inTheFuture
		self.delay = compute_delay(self.actualTime, self.scheduledTime)
		self.punctuality = punctuality(self.delay)
	def __str__(self):
		return '\t'.join([
			self.name.rjust(30),
			self.scheduledTime.strftime('%H:%M') if self.scheduledTime else '',
			self.actualTime.strftime('%H:%M') if self.actualTime else '',
			str(self.scheduledPlatform) if self.scheduledPlatform else '',
			str(self.actualPlatform) if self.actualPlatform else '',
			'' if self.inTheFuture else 'arrived',
		])

from HTMLParser import HTMLParser
class TrenitaliaTrainInfo(HTMLParser):
	def __init__(self, number):
		self.trainNumber = number
		self.info = ''
		self.inInfoSection = None
		HTMLParser.__init__(self)
		HTMLParser.feed(self, get_train_page(number, summary=True))
		HTMLParser.close(self)
	def handle_comment(self, data):
		data = ' '.join(data.strip().split()).lower()
		if data=='situazione': self.inInfoSection = True
		if data=='footer + link':
			self.inInfoSection = False
	def handle_data(self, data):
		data = ' '.join(data.strip().split()).lower()
		if self.inInfoSection:
			if data:
				self.info += data+'\n'

class TrenitaliaTrainDetail(HTMLParser):
	def __init__(self, trainNumber):
		self.name = None
		self.stations = []
		self.scheduledTimes = []
		self.times = []
		self.scheduledPlatforms = []
		self.platforms = []
		self.futureStops = []
		self.currentTag = None
		self.inTheFuture = None
		HTMLParser.__init__(self)
		HTMLParser.feed(self, get_train_page(trainNumber, summary=False))
		HTMLParser.close(self)
	def handle_comment(self, data):
		data = ' '.join(data.strip().split()).lower()
		if data=='fermate gia effettuate': self.inTheFuture = False
		if data=='fermate non ancora effettuate': self.inTheFuture = True
	def handle_starttag(self, tag, attrs):
		if tag=='h2': self.tagCleanUp(); self.currentTag = 'station'
		if tag=='h1': self.tagCleanUp(); self.currentTag = 'name'
	def tagCleanUp(self):
		if self.currentTag:
			if self.currentTag=='name': self.name=None
			elif self.currentTag=='station': self.stations.append(None); self.futureStops.append(None)
			elif self.currentTag=='scheduledTime': self.scheduledTimes.append(None)
			elif self.currentTag=='time': self.times.append(None)
			elif self.currentTag=='scheduledPlatform':self.scheduledPlatforms.append(None)
			elif self.currentTag=='platform':self.platforms.append(None)
		self.currentTag = None
	def handle_data(self, data):
		data = ' '.join(data.strip().split()).lower()
		if (data=='partenza programmata:' or
			data =='arrivo programmato:'):
			self.tagCleanUp()
			self.currentTag = 'scheduledTime'
			return
		if (data =='partenza effettiva:' or
			data =='arrivo effettivo:' or
			data =='partenza prevista:' or
			data =='arrivo previsto:'):
			self.tagCleanUp()
			self.currentTag = 'time'
			return
		if data =='binario previsto:':
			self.tagCleanUp()
			self.currentTag = 'scheduledPlatform'
			return
		if data =='binario reale:':
			self.tagCleanUp()
			self.currentTag = 'platform'
			return
		if self.currentTag=='station':
			self.stations.append(data.strip())
			self.futureStops.append(self.inTheFuture)
			self.currentTag = None
		if self.currentTag=='name':
			self.name = data.upper()
			self.currentTag = None
		if self.currentTag=='scheduledTime':
			if data:
				import datetime
				self.scheduledTimes.append(datetime.time(*[int(n) for n in data.split(':')]))
				self.currentTag = None
		if self.currentTag=='time':
			if data:
				import datetime
				try:
					self.times.append(datetime.time(*[int(n) for n in data.split(':')]))
				except:
					self.times.append(None)
				self.currentTag = None
		if self.currentTag=='scheduledPlatform':
			if data:
				try: data = int(data)
				except:
					data = None
				self.scheduledPlatforms.append(data)
				self.currentTag = None
		if self.currentTag=='platform':
			if data:
				try: data = int(data)
				except:
					data = None
				self.platforms.append(data)
				self.currentTag = None

import datetime
from google.appengine.ext import db

class Train(db.Model):
	name = db.StringProperty()
	number = db.IntegerProperty(required=True)
	checked = db.DateTimeProperty(auto_now=True)
	existent = db.BooleanProperty(default=True)
	info = db.TextProperty()
	stop_names = db.ListProperty(str)
	def get_info(self):
		try:
			self.info = TrenitaliaTrainInfo(self.number).info
			self.stops = []
			traindetail = TrenitaliaTrainDetail(self.number)
			self.name = traindetail.name
			zipped = zip(
				traindetail.stations,
				traindetail.scheduledTimes,
				traindetail.times,
				traindetail.scheduledPlatforms,
				traindetail.platforms,
				traindetail.futureStops,
				)
			[self.stops.append(TrainStop(*stop)) for stop in zipped]
		except NoTrainError:
			self.existent = False
	def __str__(self):
		return '\n'.join([
			self.name.rjust(30),
			'\n'.join([str(stop) for stop in self.stops]),
			'\n'.join(self.info),
			])
